package math;


public class Evaluation implements ArithmeticExpression {

  public static enum Operation {
    ADD("+", 2), MULT("*", 2), SUB("-", 2), NEG("-", 1);

    private String symbol;
    
    private int numberOfArguments;

    private Operation(String symbol, int numberOfArguments) {
      this.symbol = symbol;
      this.numberOfArguments = numberOfArguments;
    }

    public String getSymbol() {
      return symbol;
    }
    
    public int getNumberOfArguments() {
      return numberOfArguments;
    }

    public ArithmeticExpression operate(NumericLogicalVariable[] args) {
      switch (this){
      case ADD:
        return args[0].getValue().add(args[1].getValue());
      case MULT:
        return args[0].getValue().mult(args[1].getValue());
      case SUB:
        return args[0].getValue().sub(args[1].getValue());
      case NEG:
        return args[0].getValue().negate();
      default:
        throw new IllegalStateException("operate(" + this + ")");
      }
    }
  }

  private NumericLogicalVariable[] args;
  
  private Operation operation;

  public Evaluation(Operation operation, NumericLogicalVariable... args) {
    this.operation = operation;
    this.args = args;
  }
  
  @Override
  public int countMembers() {
    return 3;
  }

  @Override
  public ArithmeticExpression derivate(Variable var) {
    throw new RuntimeException("Evaluations can not be derivated");
  }

  @Override
  public int getPriority() {
    return 1;
  }

  public ArithmeticExpression evaluate() {
    return operation.operate(args);
  }

  @Override
  public boolean isOne() {
    return false;
  }

  @Override
  public boolean isZero() {
    return false;
  }
  
  @Override
  public boolean matches(Expression expr) {
    if (expr instanceof Evaluation) {
      Evaluation eVar = (Evaluation) expr;
      if (!operation.equals(eVar.operation))
        return false;
      if (args.length != eVar.args.length)
        return false;
      for (int i = 0; i < args.length; i++){
        if (!args[i].equals(eVar.args[i])){
          return false;
        }
      }
      return true;
    } else
      return false;
  }

  @Override
  public ArithmeticExpression simplify() {
    return this;
  }

  @Override
  public <R> R accept(ExpressionVisitor<R> visitor) {
    return visitor.visitEvaluation(this);
  }

}
